<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8" />
    <title>语法速查</title>
    <link rel="stylesheet" href="${codiconUri}" />
    <link rel="stylesheet" href="CSS-PLACEHOLDER">
    <style>
        :root {
            --fg: var(--vscode-editor-foreground);
            --link: var(--vscode-textLink-foreground);
        }

        body {
            margin: 0;
            color: var(--fg);
            font-family: 'SimSun', serif;
            font-size: min(var(--vscode-font-size), 15px);
        }

        code {
            font-family: Consolas, 'Segoe UI Mono', Monaco, monospace;
            font-size: min(var(--vscode-font-size), 15px);
        }

        #cheatsheets {
            display: block;
            align-items: center;
            cursor: pointer;
        }

        .codicon {
            display: inline-block;
        }

        .level2 .snippet-title:hover,
        .level1 .lang-name:hover {
            color: var(--link);
        }

        .level1 .lang-name {
            color: var(--vscode-symbolIcon-classForeground);
        }

        .level2 .snippet-title {
            color: var(--vscode-symbolIcon-methodForeground);
        }

        .level2 {
            padding-left: 1.2em;
            border-left: 1px solid var(--vscode-panel-border);
            margin-top: 2px;
        }

        .codicon:hover {
            color: var(--vscode-debugIcon-breakpointForeground);
        }

        #addBar {
            display: block;
            cursor: pointer;
        }

        #addLang {
            background: transparent;
            color: var(--vscode-input-foreground);
            font: inherit;
            outline: none;
            border: 1px solid transparent;
            border-width: 0 0 1px 0;
        }

        #addLang:not([readonly]) {
            border-bottom-color: var(--vscode-focusBorder);
        }

        input,
        textarea {
            background: transparent;
            color: var(--vscode-input-foreground);
            font: inherit;
            margin-top: 2px;
            outline: none;
            border-width: 0 0 1px 0;
            border-bottom-color: var(--vscode-focusBorder);
        }

        .temp-input {
            margin-left: 1em;
        }
    </style>
</head>

<body>
    <div id="cheatsheets"></div>
    <div id="addBar">
        <input id="addLang" readonly type="text" placeholder="输入语言名称，例如cpp">
        <span id="addButton" class="codicon codicon-add"
            title="添加语言,语言标识请用小写英文或缩写，如：c、cpp、csharp、dart、js、typescript、java、go、rust、php、ruby、kotlin、swift、bash、sql、html、css、json、xml、yaml、markdown、dockerfile、vue、jsx、tsx、rust、rs、lua、r、scss、graphql、objectivec、asm、shell、python"></span>
    </div>

    <script src="JS-PLACEHOLDER"></script>
    <script>
        const cheatsheets = CHEATSHEETS;

        const render = (data, parent) => {
            data.forEach(({ lang, snippets = [] }) => {
                const level1 = document.createElement('div');
                level1.className = 'level1';
                level1.dataset.lang = lang;
                parent.appendChild(level1);
                const langDiv = document.createElement('div');
                langDiv.style.display = 'block';
                level1.appendChild(langDiv);
                const langSpan = document.createElement('span');
                langSpan.className = 'lang-name';
                langSpan.textContent = lang;
                langDiv.appendChild(langSpan);
                const codiconEditSpan = document.createElement('div');
                codiconEditSpan.classList = 'codicon codicon-edit add-snippet';
                codiconEditSpan.title = '添加语法知识点';
                langDiv.appendChild(codiconEditSpan);
                snippets.forEach(({ snippet, code }) => {
                    const level2 = document.createElement('div');
                    level2.className = 'level2';
                    level2.style.display = 'none';
                    level1.appendChild(level2);
                    const snippetDiv = document.createElement('div');
                    snippetDiv.style.display = 'block';
                    level2.appendChild(snippetDiv);
                    const snippetSpan = document.createElement('span');
                    snippetSpan.className = 'snippet-title';
                    snippetSpan.textContent = snippet;
                    snippetDiv.appendChild(snippetSpan);
                    if (code) {
                        const pre = document.createElement('pre');
                        pre.className = 'level3';
                        pre.style.display = 'none';
                        level2.appendChild(pre);
                        const codeNode = document.createElement('code');
                        codeNode.className = `language-${lang}`;
                        codeNode.textContent = code;
                        pre.appendChild(codeNode);
                    } else {
                        const codiconFileSpan = document.createElement('div');
                        codiconFileSpan.classList = 'codicon codicon-code add-code';
                        codiconFileSpan.title = '添加示例代码';
                        snippetDiv.appendChild(codiconFileSpan);
                    }
                });
            });
        }

        render(cheatsheets, document.getElementById('cheatsheets'));

        const vscode = acquireVsCodeApi();

        document.addEventListener('contextmenu', e => e.preventDefault());

        document.getElementById('addButton').addEventListener('click', e => {
            const input = document.querySelector("#addLang");
            input.readOnly = false;
            input.focus();
        });

        document.getElementById('addLang').addEventListener('keydown', e => {
            if (e.key === 'Enter') {
                addLang();
            }
        });

        const addLang = () => {
            const input = document.getElementById("addLang");
            input.readOnly = true;
            const text = input.value.trim();
            if (!text) { return; }

            const cheatsheets = document.getElementById('cheatsheets');
            let child = `<div class='level1' data-lang='${text}'>
                            <div style='display: block;'>
                                <span class='lang-name'>${text}</span>
                                <span class='codicon codicon-edit add-snippet' title='添加语法知识点'></span>
                            </div>
                        </div>
                        `;
            cheatsheets.insertAdjacentHTML('beforeend', child);
            input.value = '';
            vscode.postMessage({ command: 'addLang', lang: text })
        }

        document.getElementById('cheatsheets').addEventListener('click', e => {
            if (e.target.classList.contains('add-snippet')) {
                addSnippet(e);
            }

            if (e.target.classList.contains('add-code')) {
                addCode(e);
            }

            toggleExpand(e);
        });

        const addSnippet = (e) => {
            const level1 = e.target.closest('.level1');
            const input = addTempChild(level1);

            let finished = false;
            const finish = () => {
                if (finished) return;
                finished = true;
                const snippet = input.value.trim();
                input.remove();
                if (!snippet) return;

                level1.insertAdjacentHTML('beforeend',
                    `
                    <div class='level2'>
                        <div style='display: block'>
                            <span class='snippet-title'>${snippet}</span>
                            <span class='codicon codicon-file-code add-code' title='添加示例代码'></span>
                        </div>
                    </div>
                    `
                );
                vscode.postMessage({ command: 'addSnippet', lang: level1.dataset.lang, snippet });
            }

            input.addEventListener('keydown', ev => {
                if (ev.key === 'Enter') {
                    ev.preventDefault();
                    finish();
                }
            });
            input.addEventListener('blur', finish);
        }

        const initialTextarea = (input) => {
            input.rows = 6;
            input.cols = 36;
            input.addEventListener('keydown', e => {
                if (e.key === 'Tab') {
                    e.preventDefault();
                    const start = input.selectionStart;
                    const end = input.selectionEnd;
                    input.setRangeText('    ', start, end, 'end');
                }
            });
        }

        const addTempChild = (node, isMultiline = false) => {
            let input = document.createElement('input');
            if (isMultiline) {
                input = document.createElement('textarea');
                initialTextarea(input);
            }

            input.type = 'text';
            input.className = 'temp-input';
            input.placeholder = !isMultiline ? '语法知识点, Enter提交' : '示例代码, Ctrl+Enter 提交';
            node.appendChild(input);
            input.focus();
            return input;
        }

        const addCode = (e) => {
            const level2 = e.target.closest('.level2');
            const textarea = addTempChild(level2, true);

            let finished = false;
            const finish = () => {
                if (finished) return;
                finished = true;
                const code = textarea.value.trim();
                textarea.remove();
                if (!code) {
                    return;
                }

                const lang = level2.closest('.level1').dataset.lang;
                const block = `<pre style='display: block;'><code class="language-${lang}">${code}</code></pre>`;
                level2.insertAdjacentHTML('beforeend', block);
                e.target.closest('.add-code').remove();
                const codeNode = level2.querySelector('code');
                hljs.highlightElement(codeNode);

                const snippet = level2.querySelector('.snippet-title').textContent;
                vscode.postMessage({ command: 'addCode', lang, snippet, code });
            }

            textarea.addEventListener('keydown', ev => {
                if (ev.key === 'Enter' && ev.ctrlKey) {
                    ev.preventDefault();
                    finish()
                }
            });
            textarea.addEventListener('blur', finish);
        }

        const toggleExpand = (e) => {
            const target = e.target;
            if (target.tagName === 'code') {
                return;
            } else if (target.className === 'lang-name') {
                const level2List = target.closest('.level1').querySelectorAll('.level2');
                level2List.forEach((level2) => {
                    level2.style.display = level2.style.display === 'none' ? 'block' : 'none';
                });
                return;
            } else if (target.className === 'snippet-title') {
                const pre = target.closest('.level2').querySelector('pre');
                if (pre) {
                    pre.style.display = pre.style.display === 'none' ? 'block' : 'none';
                }

                return;
            }
        }

        document.getElementById('addLang').addEventListener('blur', e => {
            addLang();
        });

        document.getElementById('cheatsheets').addEventListener('dblclick', e => {
            const target = e.target;
            const originText = target.textContent;
            const isMultiline = target.tagName === 'CODE';
            let dblInput = document.createElement('input');
            if (isMultiline) {
                dblInput = document.createElement('textarea');
                initialTextarea(dblInput);
            }

            dblInput.type = 'text';
            dblInput.value = originText;
            target.style.display = 'none';
            target.parentNode.insertBefore(dblInput, target.nextSibling);
            dblInput.focus();

            let finished = false;
            const finish = () => {
                if (finished) return;
                finished = true;
                const newText = dblInput.value.trim();
                dblInput.remove();
                if (!newText || newText === originText) {
                    target.style.display = '';
                    return;
                }

                target.textContent = newText;
                target.style.display = '';
                const level1 = target.closest('.level1');
                const originLang = level1.dataset.lang;
                const level2 = level1.querySelector('.level2');
                let originSnippet, originCode;
                if (target.className === 'lang-name') {
                    level1.dataset.lang = newText;
                } else if (target.className === 'snippet-title') {
                    originSnippet = originText;
                } else if (isMultiline) {
                    target.class = `language-${originLang}`;
                    originCode = originText;
                    hljs.highlightElement(target);
                }

                const lang = level1.dataset.lang;
                const snippet = level2?.querySelector('.snippet-title')?.textContent ?? null;
                const code = level2?.querySelector('code')?.textContent ?? null;
                vscode.postMessage({
                    command: 'update', lang, snippet, code, originLang, originSnippet, originCode
                });
            };

            dblInput.addEventListener('keydown', e => {
                if ((e.key === 'Enter' && (e.ctrlKey || !isMultiline))) {
                    e.preventDefault();
                    finish();
                }
            });
            dblInput.addEventListener('blur', () => {
                finish();
            });
        });

        hljs.highlightAll();
    </script>
</body>

</html>